1.方法交换
我们可以将Method Swizzling功能封装为类方法,作为NSObject的类别,这样我们后续调用也会方便些。
NSObject+Swizzling.h1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (Swizzling)
/**
 方法交换
 @param originalSelector 源方法
 @param swizzledSelector 新方法
*/
+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector
                        andSwizzledSelector:(SEL)swizzledSelector;
                        
@end
NS_ASSUME_NONNULL_END
NSObject+Swizzling.m1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#import "NSObject+Swizzling.h"
#import<objc/runtime.h>
 NSObject (Swizzling)
+ (void)methodSwizzlingWithOriginalSelector:(SEL)originalSelector
                        andSwizzledSelector:(SEL)swizzledSelector {
    Class class = [self class];
    //原有方法
    Method originalMethod = class_getInstanceMethod(class, originalSelector);
    //替换原有方法的新方法
    Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
    //先尝试給源SEL添加IMP,这里是为了避免源SEL没有实现IMP的情况
    BOOL didAddMethod = class_addMethod(class,originalSelector,
    method_getImplementation(swizzledMethod),
    method_getTypeEncoding(swizzledMethod));
    if (didAddMethod) {//添加成功:说明源SEL没有实现IMP,将源SEL的IMP替换到交换SEL的IMP
        class_replaceMethod(class,swizzledSelector,
        method_getImplementation(originalMethod),
        method_getTypeEncoding(originalMethod));
    } else {//添加失败:说明源SEL已经有IMP,直接将两个SEL的IMP交换即可
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
ViewController.m1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@implementation ViewController (Swizzling)
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 交换对象方法
        [self methodSwizzlingWithOriginalSelector:@selector(viewWillAppear:) andSwizzledSelector:@selector(lczViewWillAppear:)];
        
        // 交换类方法
        [object_getClass([LibDevModel class]) methodSwizzlingWithOriginalSelector:@selector(onScanOver:) andSwizzledSelector:@selector(lczOnScanOver:)];
    });
}
2.消息转发
2.1 转发对象方法
LibDevModel+Swizzling.h1
2
3
4
5
6
7
8
9
NS_ASSUME_NONNULL_BEGIN
@interface LibDevModel (Swizzling)
- (void)lczTimerCancel;
@end
NS_ASSUME_NONNULL_END
LibDevModel+Swizzling.m1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@implementation LibDevModel (Swizzling)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    // 获取 aSelector 的方法签名
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) { // 如果无法获取
        // 判断 ViewController 是否能够响应 aSelector
        if ([ViewController instancesRespondToSelector:aSelector]) {
            // 获取 ViewController 中 aSelector 的方法签名
            signature = [ViewController instanceMethodSignatureForSelector:aSelector];
        }
    }
    return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([ViewController instancesRespondToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:[ViewController new]];
    }
}
GLGuardViewController.m1
2
3
4
5
6
7
8
9
10
11
12
@interface GLGuardViewController ()
@end
@implementation GLGuardViewController
- (void)lczTimerCancel {
    NSLog(@"调用了");
}
2.2 转发类方法
LibDevModel+Swizzling.h1
2
3
4
5
6
7
8
9
NS_ASSUME_NONNULL_BEGIN
@interface LibDevModel (Swizzling)
+ (void)lczTimerCancel;
@end
NS_ASSUME_NONNULL_END
LibDevModel+Swizzling.m1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18+ (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    // 获取 aSelector 的方法签名
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) { // 如果无法获取
        // 判断 ViewController 是否能够响应 aSelector
        if ([GLGuardViewController respondsToSelector:aSelector]) {
            // 获取 ViewController 中 aSelector 的方法签名
            signature = [GLGuardViewController methodSignatureForSelector:aSelector];
        }
    }
    return signature;
}
+ (void)forwardInvocation:(NSInvocation *)anInvocation {
    if ([GLGuardViewController respondsToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:[GLGuardViewController class]];
    }
}
GLGuardViewController.m1
2
3
4
5
6
7
8
9
10
11
12
@interface GLGuardViewController ()
@end
@implementation GLGuardViewController
+ (void)lczTimerCancel {
    NSLog(@"调用了");
}